﻿#!/usr/bin/env python
# Stars.py: starfield animation
# 26/05/09
# Copyright(c) 2009 Victor Freire e Cássio Espindola. All rights reserved.
# Python 2.6.2
import pygame
import random
import copy
import math

import Timer

STAR_COLOR_MAX = (255, 255, 255)
STAR_COLOR_MIN = (190, 190, 190)

class Star:
    def __init__(self, x, y, angle, speed, max_size):
        self.x = x
        self.y = y
        self.size = 0
        self.max_size = max_size
        self.angle = angle
        self.speed = speed
        self.new_speed(speed)
        self.star_color = (random.randint(STAR_COLOR_MIN[0], STAR_COLOR_MAX[0]),) * 3
        
        
    def draw(self, dest):
        if self.size:
            dest.fill(self.star_color, (self.x - (self.size / 2), self.y - (self.size / 2), self.size, self.size))
        
        
    def new_speed(self, speed):
        self.vx = int((speed * math.cos(math.radians(self.angle))) * (self.max_size / 10.))
        self.vy = int((speed * math.sin(math.radians(self.angle))) * (self.max_size / 10.))
        
    def move(self, mult_factor):
        self.x += self.vx * mult_factor
        self.y += self.vy * mult_factor
        
    def __str__(self):
        return "pos: (%f, %f) -- vel: (%d, %d)" % (self.x, self.y, self.vx, self.vy)
        


class Stars:
    def __init__(self, screen_w, screen_h, accelerate):
        self.stars = []
        self.max_stars = 100
        self.screen_w = screen_w
        self.screen_h = screen_h
        self.origin_box = (screen_w / 2, screen_h / 2, 25, 25)
        self.accel_speed = 60 if accelerate else 0
        
        self.max_speed = (400, 1200)
        self.speed = self.max_speed if not self.accel_speed else (0, (self.max_speed[1] - self.max_speed[0]) / 4)
        
        self.min_star_size = 0.80 #if higher increases the star density in the center of the screen
        self.lowest_max_star_size = 1000
        self.max_star_size = 4.0
        
        self.new_stars(self.max_stars, True)
    
    def get_speed(angle):
        return vx, vy
                       
    def new_stars(self, num, start):
        for i in xrange(num):
            angle = random.randint(0, 360)
            speed = random.randint(self.speed[0], self.speed[1]) if not self.accel_speed else random.randint(int(self.speed[0]), int(self.speed[1]))
                        
            starx = self.screen_w / 2
            stary = self.screen_h / 2
                        
            newstar = Star(starx, stary, angle, speed, random.randint(1000 , int(self.max_star_size * 1000)) / 1000.)
            
            if start: #set the stars to 'random' position in screen
                newstar.move(random.randint(3, 10))
            else:
                newstar.move(random.randint(0, 5))
                        
            self.stars.append(newstar)
            
    
    def main(self, dest, mult_factor):
        stars_num = len(self.stars)
        stars_new = [] 
        for i in xrange(stars_num):
            s = self.stars[i]
            s.draw(dest)
            
            if self.accel_speed:
                s.new_speed(random.randint(int(self.speed[0]), int(self.speed[1])))
            
            s.move(mult_factor)            
                        
            xdiff = abs(s.x - (self.screen_w / 2))
            ydiff = abs(s.y - (self.screen_h / 2))
            s.size = self.min_star_size + ((xdiff * s.max_size) / self.screen_w) + ((ydiff * s.max_size) / self.screen_h)
            
            if 0 < s.x < self.screen_w and 0 < s.y < self.screen_h: stars_new.append(copy.copy(s))
        
        self.stars = stars_new
        
        if self.accel_speed:
            if self.speed[0] > self.max_speed[0] or self.speed[1] > self.max_speed[1]:
                self.accel_speed = 0
                self.speed = self.max_speed
            self.speed = (self.speed[0] + self.accel_speed * mult_factor, self.speed[1] + self.accel_speed * mult_factor)
            
        if stars_num < self.max_stars:
            self.new_stars(random.randint(1, ((self.max_stars - stars_num) / 2 + 1)), False)
        
    
    
def handle_input():
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            return False
        
        elif e.type == pygame.KEYDOWN:
            if e.key == pygame.K_ESCAPE:
                return False
        #    elif e.key == pygame.K_LEFT:
        #        pov.turn_left(2)
        
            
    return True



if __name__ == '__main__':
    screenwidth = 640
    screenheight = 480
    screenflags = 0
    screenflags = pygame.FULLSCREEN
    screenbpp = 32
    
    SHOW_FPS = True
    
   
        
    
    pygame.init()
    try:
        screen = pygame.display.set_mode((screenwidth, screenheight), screenflags , screenbpp) 
    except pygame.error, msg:   
        print "Error: failed to initialize display -", msg
     
    pygame.display.set_caption('Starfield Demo')
    
    
    
    
    
    class FPS_counter:
        def __init__(self):
            self.frames = 0
            self.myfont = pygame.font.SysFont("courier new", 14, False, False)
                
        def average(self):
            return self.frames / (pygame.time.get_ticks() / 1000.)  
        
        def draw_counter(self, dest, screenwidth):
            fpstext = self.myfont.render("FPS: %d" % self.average(), False, (0,255,0)).convert()
            screen.blit(fpstext, (screenwidth - 83, 10))
        
        def finished_frame(self):
            self.frames += 1
            
    FPS = FPS_counter()
    
    
    
    
    
    stars = Stars(screenwidth, screenheight, True)
    #Main Loop
    while handle_input():
        Timer.Timer.update()
        mult_factor = Timer.Timer.get_mult_factor()
        
        screen.fill((0, 0, 0)) #clear screen
        stars.main(screen, mult_factor)
        
        if SHOW_FPS: FPS.draw_counter(screen, screenwidth)
        
        pygame.display.flip()
        FPS.finished_frame()
        
    
    pygame.quit()
    
    
